終於輪到迴圈了(其實也才剛開始三篇而已XD)!說到迴圈大家一定不陌生,除了最初的起點Hello!world!
以外,應該就是九九乘法表了,那當迴圈融入前端框架時,會迸出什麼火花,讓我們來看看吧!
在上一篇文章中大家都知道Vue.js中的if
寫作v-if
,那for
呢?
v-for
嗎?沒錯!就是v-for
!直接來看用法吧:
<div id="todoList">
<div v-for="list in lists">
{{list.item}}
</div>
</div>
JavaScript
let listData = {
//lists屬性中存著陣列
lists:[
//陣列中擁有多個相同key的物件
{item:'學Vue.js'},
{item:'學React'},
{item:'學Angular2'}
]
}
let todoList = new Vue({
el:'#todoList',
data:listData,
})
這一次從JavaScript
的部分先說,首先像平常一樣定義一個listData
物件,可以看到裡面有一個紀錄陣列的lists
,陣列裡面的內容則是一個個擁有相同key
的物件,差別是值不一樣,而我們new的Vue物件抓取外層的div
,讓該div
的內容都可以綁定listData
的資料。
好的,那再來是HTML
的部分,我們把v-for
寫在內層,裡面的值是list in lists
這裡的語法和JavaScript
一樣,v-for
會將lists
也就是listData
中的陣列資料一個一個讀取並把值放進list
中,再往更裡面看一點,內層的div
目前綁定的資料是list.item
也就是lists
中每一個物件的item
值,所以設定了v-for
的div
會被迴圈重覆輸出,唯一會變的只有{{list.item}}
的值而已,來看看綁定後的結果吧!
登愣!原本只有一個的div
也變成了三個,而且裡面的值也都被綁定item
了!
當然,只要是在data
中的資料,就算沒在lists
裡也可以綁定,而且很貼心的是,v-for
還可以有第二個參數,來紀錄目前是陣列中的第幾項:
HTML
<div id="todoList">
<!--在這裡增加了第二個參數index,記得兩個參數以上要用括號-->
<div v-for="(list,index) in lists">
{{index}}.{{titleText}} - {{list.item}}
</div>
</div>
JavaScript
//增加一個titleText屬性
let listData = {
titleText:'要做的事情',
lists:[
{item:'學Vue.js'},
{item:'學React'},
{item:'學Angular2'}
]
}
HTML
中為v-for
增加了第二個參數,他會記錄著目前是陣列中的第幾個索引,記得索引值都是從0開始哦!除此之外我也在JavaScript
中的listData
增加了一的屬性titleText
,執行他吧!
內容就分別是索引的index
加上listData
的titleText
還有lists
的item
,這邊特別的是字串的組合不需要使用加號,不過說不定其他前端框架也是這樣,因為小弟碰過的框架目前只有Vue.js,所以可以請板上大大們留言分享一下XD,那我們繼續下去吧!
其實v-for
和v-if
會遇到的問題一樣,沒辦法本是同根身,總會有些習慣相同,就是為了效能,v-for
會在我們調整lists
順序的時候只對不同的地方做替換而已,我們把今天學到的v-for
用法加進昨天的例子裡來看這個狀況:
HTML
<div id="formList">
<div v-for="list in lists">
{{titleText}}{{list.item}}:
<!--用第一天學到的v-bind綁定placeholder屬性為list.item的值-->
<input :placeholder="list.item">
</div>
<!--昨天是切換輸入,今天是反轉陣列-->
<input type="button" value="反轉陣列" @click="changeSort">
</div>
JavaScript
let listData = {
titleText:'請輸入',
lists:[
{item:'姓名'},
{item:'信箱'},
{item:'電話'}
]
}
let listMethods = {
changeSort: () => {
//反轉陣列
listData.lists.reverse()
}
}
let formList = new Vue({
el:'#formList',
data:listData,
methods:listMethods,
})
Vue.js處理過的畫面會如下:
看起來也滿像樣的,對吧?不過這不是重點,讓我們來看看以下操作:
我先在第一個input
輸入姓名,之後反轉陣列lists
中的元素,Vue.js的動態綁定資料會迅速的刷新畫面,原本第一個的姓名跑到最後一個,電話跑到第一個,但是有沒有一個強烈的既視感,那就是input
的value
值還在啊!因為Vue.js不會重新繪製,而是只刷新了原本input
不同的地方,也就是placeholder
。好的,既然問題發生了,還是得解決,想想昨天v-if
的處理方式,怎麼辦呢?
key
嗎?對!就是他!不過設定方法和昨天稍微有點不同,我們必須用v-bind
的方式去綁定key
值,像下方這樣:
HTML
<div id="formList">
<div v-for="list in lists">
{{titleText}}{{list.item}}:
<!--增加v-bind設定key值-->
<input :placeholder="list.item" :key="list.id">
</div>
<input type="button" value="反轉陣列" @click="changeSort">
</div>
JavaScript
let listData = {
titleText:'請輸入',
//為lists中的各個物件加上id
lists:[
{id:'name',item:'姓名'},
{id:'mail',item:'信箱'},
{id:'tel',item:'電話'}
]
}
HTML
的部分就像上面說的,用v-bind
綁定一個key
屬性,他的值是list.id
,所以在JavaScipt
中要記得在listData
中的lists
中的物件加入id
的資料,加上key
值的他們,如果重新綁定就會進行重新繪製了!
然而因為重新繪製的關係,所以一反轉陣列內容,我們輸入過的value
自然就不見啦!而官方文件上面也有說建議大家在使用v-for
的時候,除非是有特殊原因需要刻意的讓效能提升,不然都盡量綁定key
屬性。
以下先用上方加入key
的程式碼下去說明,重複的部分就不會再打上去了!
增加項目非常簡單,直接對listData
內的lists
做push()
,Vue.js就會幫你處理好剩下的事情!
移除和增加一樣,直接對listData
的lists
下splice()
就可以了。
這邊我補充一下splice()
的用法,上面我用在移除的時候給他兩個參數listData.lists.splice(3,1)
,因為前一次我在lists
中push()
了age
;age
在陣列中的索引為3,所以就是從第3個索引開始移除掉1個,也就是把age
給移除。
JavaScript
有許多操作陣列的function
,但並不是所有function
都會改變原有的陣列內容,有些是回傳新的陣列,例如官網舉例篩選資料用的filter()
、合併兩個陣列的concat()
或是截取陣列內容的slice()
,怎麼辦?
其實很簡單,非常非常簡單,就把處理後的資料指定回去而已。這邊我以concat()
說明,其他兩個方式的做法也一樣。
conosle的第一行我先新增另一個陣列arr1
,之後用concat()
把data
的lists
陣列和arr1
做合併,但是concat()
不會異動原本的lists
,所以我在同時也把他指定回去。
lists
中第二個索引的值時,千千萬萬別這麼做listData.lists[2] = {id:'test',item:'測試'}
,這樣會讓Vue.js無法動態刷新畫面,解套方法當然是有,可以改成Vue.set(list, index, value)
讓Vue.js刷新,以下範例:$set
寫成這樣:formList.$set(listData.lists, 2, {id:'test',item:'測試'})
listData.lists.length = 2
,也不會被Vue.js抓到哦!如果要移除元素,請使用上面提到的splice()
來做處理。剛剛打完文章,順手看了一下Vue.js官方文件的目錄,突然覺得未來的路還好長XD,不過相信It這條路不孤單,大家都會一起走下去的對吧!哈哈哈。
最後感謝各位大大的觀看,如果文章中有任何錯誤或是講解不清楚的部分,還請留言告訴我,我會盡快修正!謝謝大家